package com.example.socket.filter.session;

import com.example.socket.core.Session;
import com.example.socket.filter.session.SessionEvent.Type;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.example.socket.core.SessionKeys.ATT_IGNORE_EVENT;

public class SessionEventDispacher implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    /**
     * 注册容器中的Session事件
     */
    protected void initializer() {
        Map<String, SessionListener> allListener = applicationContext.getBeansOfType(SessionListener.class);
        for (SessionListener listener : allListener.values()) {
            addListener(listener);
        }
    }

    public void addListener(SessionListener listener) {
        synchronized (this) {
            List<SessionListener> type2listener = listeners.get(listener.getType());
            if (type2listener == null) {
                type2listener = new ArrayList<>();
                listeners.put(listener.getType(), type2listener);
            }
            type2listener.add(listener);
        }
    }

    /** 事件监听器 */
    protected Map<Type, List<SessionListener>> listeners = new HashMap<>();

    /** 会话替换事件 */
    protected void fireReplacedEvent(Object identity, Session current, Session replaced) {
        List<SessionListener> listener = listeners.get(Type.REPLACED);
        if (listener == null) {
            return;
        }
        if (!ATT_IGNORE_EVENT.getValue(current, false)) {
            onEvent(listener, new SessionReplacedEvent(SessionEventCause.ENFORCE_LOGOUT, identity, current, replaced));
        }
    }

    private void onEvent(List<SessionListener> listeners, SessionEvent event) {
        for (SessionListener listener : listeners) {
            listener.onEvent(event);
        }
    }

    /** 发出完成身份验证事件 */
    protected void fireIdentifiedEvent(Object identity, Session session) {
        List<SessionListener> listener = listeners.get(Type.IDENTIFIED);
        if (listener == null) {
            return;
        }
        if (!ATT_IGNORE_EVENT.getValue(session, false)) {
            onEvent(listener, new SessionEvent(SessionEventCause.NORMAL, Type.IDENTIFIED, identity, session));
        }
    }

    /** 发出关闭事件 */
    protected void fireClosedEvent(Object identity, int cause, Session session) {
        List<SessionListener> listener = listeners.get(Type.CLOSED);
        if (listener == null) {
            return;
        }
        if (!ATT_IGNORE_EVENT.getValue(session, false)) {
            onEvent(listener, new SessionEvent(cause, Type.CLOSED, identity, session));
        }
    }

    /** 发出钝化事件 */
    protected void firePassivatedEvent(Object identity, int cause, Session session) {
        List<SessionListener> listener = listeners.get(Type.PASSIVATED);
        if (listener == null) {
            return;
        }
        if (!ATT_IGNORE_EVENT.getValue(session, false)) {
            onEvent(listener, new SessionEvent(cause, Type.PASSIVATED, identity, session));
        }
    }

    /** 发出活化事件 */
    protected void fireActivedEvent(Object identity, int cause, Session session) {
        List<SessionListener> listener = listeners.get(Type.ACTIVATED);
        if (listener == null) {
            return;
        }
        if (!ATT_IGNORE_EVENT.getValue(session, false)) {
            onEvent(listener, new SessionEvent(cause, Type.ACTIVATED, identity, session));
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}